import { HttpStatus, Injectable, Logger } from '@nestjs/common';
import { HttpErrorByCode } from '@nestjs/common/utils/http-error-by-code.util';
import { InjectRepository } from '@nestjs/typeorm';
import { map } from 'rxjs';
import { User } from 'src/entities/user.entity';
import { Repository } from 'typeorm';
import { EmployeeService } from '../hrm/services/employee.service';
import { OrgsId } from 'src/globals/orgsConst';

@Injectable()
export class UserService {
  private logger = new Logger(UserService.name);
  constructor(
    @InjectRepository(User)
    private readonly userRepository: Repository<User>,
    private readonly employeeService: EmployeeService,
  ) {}

  async getAll(
    filter: {
      selectedSort:
        | 'lastName:ASC'
        | 'lastName:DESC'
        | 'firstName:ASC'
        | 'firstName:DESC'
        | '';
      selectedCities: string[];
      selectedOrgs: string[];
      selectedPositions: string[];
    },
    userOrgUUID: string | null,
  ) {
    const queryB = this.userRepository
      .createQueryBuilder('user')
      .select([
        'user.id as id',
        'user.lastNameRu as "lastNameRu"',
        'user.lastNameEn as "lastNameEn"',
        'user.firstNameRu as "firstNameRu"',
        'user.firstNameEn as "firstNameEn"',
        'user.positionNameRu as "positionNameRu"',
        'user.positionNameEn as "positionNameEn"',
        'user.cityRu as "cityRu"',
        'user.cityEn as "cityEn"',
        'user.orgNameRu as "orgNameRu"',
        'user.orgNameEn as "orgNameEn"',
      ])
      .where('user.hideEmployee = :hideVal', { hideVal: false });

    // создаем клон для кейса с двумя запросами к бд с противоположными условиями
    const queryB2 = queryB.clone();

    // проверяем что мы получили от пользователя его орг
    if (userOrgUUID && userOrgUUID.length > 0) {
      // фильтры пустые
      if (
        filter.selectedCities.length === 0 &&
        filter.selectedOrgs.length === 0 &&
        filter.selectedPositions.length === 0 &&
        filter.selectedSort === ''
      ) {
        // данные для НФ
        if (userOrgUUID === OrgsId.NFOrgUid) {
          return await queryB
            .andWhere('user.orgUuid IN (:...orgIds)', {
              orgIds: [
                OrgsId.AvantOrgUid,
                OrgsId.QvantOrgUid,
                OrgsId.SMMOrgUid,
              ],
            })
            .orderBy('user.lastNameRu', 'ASC')
            .getRawMany();
        } else if (
          userOrgUUID === OrgsId.SMOrgUid ||
          userOrgUUID === OrgsId.TGOrgUid ||
          userOrgUUID === OrgsId.RoiOrgUid ||
          userOrgUUID === OrgsId.NMOrguid
        ) {
          queryB2.andWhere('user.orgUuid NOT IN (:...orgIds)', {
            orgIds: [userOrgUUID, OrgsId.NFOrgUid],
          });
        } else {
          queryB2.andWhere('user.orgUuid != :orgId', { orgId: userOrgUUID });
        }

        const ourOrgUsers = await queryB
          .andWhere('user.orgUuid = :orgId', { orgId: userOrgUUID })
          .orderBy('user.lastNameRu', 'ASC')
          .getRawMany();

        const allUsers = await queryB2
          .orderBy('user.lastNameRu', 'ASC')
          .getRawMany();
        return [...ourOrgUsers, ...allUsers];
      } else {
        // фильтры не пустые и орг не пустой
        const sortArr = filter.selectedSort.split(':');
        const orderByQ =
          sortArr.length > 1
            ? ['user.' + sortArr[0] + 'Ru', sortArr[1]]
            : ['user.lastNameRu', 'ASC'];

        if (filter.selectedCities.length > 0) {
          queryB.andWhere('user.cityRu = any(:cityRu)', {
            cityRu: filter.selectedCities,
          });
        }

        if (filter.selectedOrgs.length > 0) {
          queryB.andWhere('user.orgNameRu = any(:orgNameRu)', {
            orgNameRu: filter.selectedOrgs,
          });
        }

        if (filter.selectedPositions.length > 0) {
          queryB.andWhere('user.positionNameRu = any(:positionNameRu)', {
            positionNameRu: filter.selectedPositions,
          });
        }
        // данные для НФ
        if (userOrgUUID === OrgsId.NFOrgUid) {
          queryB.andWhere('user.orgUuid IN (:...orgIds)', {
            orgIds: [OrgsId.AvantOrgUid, OrgsId.QvantOrgUid, OrgsId.SMMOrgUid],
          });
        }
        // данные для SM TG Roitek
        if (
          userOrgUUID === OrgsId.SMOrgUid ||
          userOrgUUID === OrgsId.TGOrgUid ||
          userOrgUUID === OrgsId.RoiOrgUid ||
          userOrgUUID === OrgsId.NMOrguid
        ) {
          queryB.andWhere('user.orgUuid NOT IN (:...orgIds)', {
            orgIds: [OrgsId.NFOrgUid],
          });
        }

        return await queryB
          .orderBy(orderByQ[0], orderByQ[1] as 'ASC' | 'DESC')
          .getRawMany();
      }
    }
    // работа с фильтрами на главной
    const sortArr = filter.selectedSort.split(':');
    const orderByQ =
      sortArr.length > 1
        ? ['user.' + sortArr[0] + 'Ru', sortArr[1]]
        : ['user.lastNameRu', 'ASC'];

    if (filter.selectedCities.length > 0) {
      queryB.andWhere('user.cityRu = any(:cityRu)', {
        cityRu: filter.selectedCities,
      });
    }

    if (filter.selectedOrgs.length > 0) {
      queryB.andWhere('user.orgNameRu = any(:orgNameRu)', {
        orgNameRu: filter.selectedOrgs,
      });
    }

    if (filter.selectedPositions.length > 0) {
      queryB.andWhere('user.positionNameRu = any(:positionNameRu)', {
        positionNameRu: filter.selectedPositions,
      });
    }

    return await queryB
      .orderBy(orderByQ[0], orderByQ[1] as 'ASC' | 'DESC')
      .getRawMany();
  }

  async getFavorites(body: {
    favorites: string[];
    filter: {
      selectedSort:
        | 'lastName:ASC'
        | 'lastName:DESC'
        | 'firstName:ASC'
        | 'firstName:DESC'
        | '';
      selectedCities: string[];
      selectedOrgs: string[];
      selectedPositions: string[];
    };
  }) {
    const sortArr = body.filter.selectedSort.split(':');
    const orderByQ =
      sortArr.length > 1
        ? ['user.' + sortArr[0] + 'Ru', sortArr[1]]
        : ['user.lastNameRu', 'ASC'];

    const queryB = this.userRepository
      .createQueryBuilder('user')
      .select([
        'user.id as id',
        'user.lastNameRu as "lastNameRu"',
        'user.lastNameEn as "lastNameEn"',
        'user.firstNameRu as "firstNameRu"',
        'user.firstNameEn as "firstNameEn"',
        'user.positionNameRu as "positionNameRu"',
        'user.positionNameEn as "positionNameEn"',
        'user.cityRu as "cityRu"',
        'user.cityEn as "cityEn"',
        'user.orgNameRu as "orgNameRu"',
        'user.orgNameEn as "orgNameEn"',
      ])
      .where('user.hideEmployee = :hideVal', { hideVal: false })
      .andWhere('user.id = any(:favs)', {
        favs: body.favorites,
      });

    if (body.filter.selectedCities.length > 0) {
      queryB.andWhere('user.cityRu = any(:cityRu)', {
        cityRu: body.filter.selectedCities,
      });
    }

    if (body.filter.selectedOrgs.length > 0) {
      queryB.andWhere('user.orgNameRu = any(:orgNameRu)', {
        orgNameRu: body.filter.selectedOrgs,
      });
    }

    if (body.filter.selectedPositions.length > 0) {
      queryB.andWhere('user.positionNameRu = any(:positionNameRu)', {
        positionNameRu: body.filter.selectedPositions,
      });
    }

    return await queryB
      .orderBy(orderByQ[0], orderByQ[1] as 'ASC' | 'DESC')
      .getRawMany();
  }

  async getUserById(id: string) {
    const userWithoutHead1Position: User = await this.userRepository
      .createQueryBuilder('user')
      .select([
        'user.id as id',
        'user.lastNameRu as "lastNameRu"',
        'user.lastNameEn as "lastNameEn"',
        'user.firstNameRu as "firstNameRu"',
        'user.firstNameEn as "firstNameEn"',
        'user.positionNameRu as "positionNameRu"',
        'user.positionNameEn as "positionNameEn"',
        'user.cityRu as "cityRu"',
        'user.cityEn as "cityEn"',
        'user.orgNameRu as "orgNameRu"',
        'user.orgNameEn as "orgNameEn"',
        'user.phone as "phone"',
        'user.workplace as "workplace"',
        'user.birthDate as "birthDate"',
        'user.email as "email"',
        'user.unitNameRu as "unitNameRu"',
        'user.unitNameEn as "unitNameEn"',
        'user.unitNameEn as "unitNameEn"',
        'user.head1Id as "head1Id"',
        'user.head1NameRu as "head1NameRu"',
        'user.head1NameEn as "head1NameEn"',
      ])
      .where('user.id = :id', { id: id })
      .getRawOne();

    const head1Info = await this.userRepository
      .createQueryBuilder('user')
      .select([
        'user.id as "head1Id"',
        'user.lastNameRu as "head1LastNameRu"',
        'user.lastNameEn as "head1LastNameEn"',
        'user.firstNameRu as "head1FirstNameRu"',
        'user.firstNameEn as "head1FirstNameEn"',
        'user.positionNameRu as "head1PositionNameRu"',
        'user.positionNameEn as "head1PositionNameEn"',
      ])
      .where('user.id = :id', { id: userWithoutHead1Position?.head1Id })
      .getRawOne();

    return { ...userWithoutHead1Position, ...head1Info };
  }

  async setFavorite(data: { userId: string; favoriteId: string }) {
    const favorites: { data: any[] } = await this.userRepository
      .createQueryBuilder('user')
      .select(['user.favorites as data'])
      .where('user.id = :id', { id: data.userId })
      .getRawOne();

    // такой избранный уже есть
    if (favorites.data.includes(data.favoriteId)) {
      favorites.data = favorites.data.filter((fav) => fav !== data.favoriteId);
    } else {
      favorites.data = [...favorites.data, data.favoriteId];
    }

    return await this.userRepository
      .createQueryBuilder()
      .update(User)
      .set({ favorites: favorites.data })
      .where('id = :id', { id: data.userId })
      .returning(['favorites'])
      .execute();
  }

  getPhoto(id: string) {
    if (id) {
      if (id.length === 0) {
        throw new HttpErrorByCode[HttpStatus.BAD_REQUEST]();
      }
      return this.employeeService.employeePhoto(id).pipe(
        map((res) => {
          return res;
        }),
      );
    }
    throw new HttpErrorByCode[HttpStatus.BAD_REQUEST]();
  }
}
